/**
 * 防抖函数
 * @param func 要执行的函数
 * @param wait 延迟的时间（毫秒）
 * @param immediate 是否立即执行
 * @returns 防抖后的函数
 */
function debounce<T extends (...args: any[]) => any>(
  func: T,
  wait = 100,
  immediate = false
) {
  let timeout: ReturnType<typeof setTimeout> | null;
  let resolveList: ((value: ReturnType<T>) => void)[] = [];
  let isInvoked = false;

  const later = async (args: Parameters<T>) => {
    timeout = null;
    isInvoked = false;
    if (!immediate) {
      const result = await func(...args);
      resolveList.forEach((resolve) => resolve(result));
      resolveList = [];
    }
  };

  const debounced = (...args: Parameters<T>): Promise<ReturnType<T>> => {
    return new Promise((resolve) => {
      const callNow = immediate && !isInvoked;
      isInvoked = true;

      if (timeout !== null) {
        clearTimeout(timeout);
      }

      if (callNow) {
        Promise.resolve(func(...args)).then(resolve);
      } else {
        resolveList.push(resolve);
        timeout = setTimeout(() => later(args), wait);
      }
    });
  };

  debounced.cancel = () => {
    if (timeout !== null) {
      clearTimeout(timeout);
      timeout = null;
    }
    isInvoked = false;
    resolveList = [];
  };

  return debounced;
}

export default debounce;
